package com.ylz.sjzx.sio.room.utils;

import cn.hutool.core.util.StrUtil;
import com.corundumstudio.socketio.Transport;
import com.corundumstudio.socketio.handler.TransportState;
import com.corundumstudio.socketio.messages.OutPacketMessage;
import com.corundumstudio.socketio.protocol.Packet;
import com.corundumstudio.socketio.protocol.PacketType;
import com.corundumstudio.socketio.transport.NamespaceClient;
import com.ylz.sjzx.sio.common.core.enums.SocketModel;
import com.ylz.sjzx.sio.common.core.utils.DateUtil;
import com.ylz.sjzx.sio.common.core.utils.ReactUtil;
import com.ylz.sjzx.sio.room.entity.LiveJoinDetail;
import com.ylz.sjzx.sio.room.entity.QuitUserResp;
import com.ylz.sjzx.sio.room.entity.User;
import com.ylz.sjzx.sio.sdk.client.session.IMSession;
import com.ylz.sjzx.sio.sdk.client.utils.SessionUtil;
import com.ylz.sjzx.sio.sdk.model.BaseSocketModel;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @author wiqi
 * @version 1.0
 * @date 2020/12/10
 */
@Slf4j
public class UserUtil {

    /**
     * 正常发送管道消息
     *
     * @param session
     * @param message
     */
    public static void sendMesage(IMSession session, BaseSocketModel message) {
        SessionUtil.sendMesage(session, message);
    }

    /**
     * 刚登录用户专用
     * 临时解决方式
     *
     * @param session
     * @param message
     * @param time
     */
    @SneakyThrows
    public static void sendRetryMesage(IMSession session, BaseSocketModel message, Integer time) {
        doSendRetryMesage(session, message, time, true);

    }

    /**
     * 刚登录用户专用
     * 临时解决方式
     *
     * @param session
     * @param message
     * @param time
     */
    @SneakyThrows
    public static void doSendRetryMesage(IMSession session, BaseSocketModel message, Integer time,
                                         boolean firstTime) {
        NamespaceClient socketIOClient1 = (NamespaceClient) session.getSocketIOClient();

        time = --time;
        if (time < 0) {
            return;
        }
        if (!firstTime) {
            Thread.sleep(40);
        }
        log.debug("第{}次了", time);
        ChannelFuture channelFuture = null;
        //发消息模块
        if (Objects.equals(SocketModel.channel, session.getSocketModel())) {
            channelFuture = sendLoginMesage(session.getChannel(), new TextWebSocketFrame(message.toCmdMessage()));
        } else {
            //消息包
            Packet packet = new Packet(PacketType.MESSAGE);
            packet.setSubType(PacketType.EVENT);
            packet.setName(message.getAction().getValue());
            if (message.isNeedtoParam()) {
                packet.setData(Arrays.asList(message.getParam()));
            } else {
                packet.setData(Arrays.asList(message.toMessage()));
            }
            channelFuture = doGetchannelFuture(socketIOClient1, packet);
        }

        log.debug("channelFuture{}", channelFuture);
        if (channelFuture != null) {
            Integer finalTime = time;
            channelFuture.addListener(iChannelFuture -> {
                log.debug("进来channelFuture{}" + iChannelFuture.isSuccess());
                if (!iChannelFuture.isSuccess()) {
                    doSendRetryMesage(session, message, finalTime, false);
                    return;
                }
            });
        } else {
            doSendRetryMesage(session, message, time, false);
            return;
        }

    }

    /**
     * 非常骚 在初始绑定的时候发消息用
     *
     * @param socketIOClient 客户端
     * @param packet         消息体
     * @return
     */
    @SneakyThrows
    private static ChannelFuture doGetchannelFuture(NamespaceClient socketIOClient, Packet packet) {
        //反射获取BaseClient 的channels
        Map<Transport, TransportState> channels =
                (Map<Transport, TransportState>) ReactUtil
                        .getFieldValueByFieldName("channels", socketIOClient.getBaseClient());

        TransportState state = channels.get(socketIOClient.getBaseClient().getCurrentTransport());

        if (state.getChannel() == null || (!state.getChannel().isWritable())) {
            return null;
        }

        log.debug("刷数据了");
        state.getPacketsQueue().add(packet);
        return sendLoginMesage(state.getChannel(), new OutPacketMessage(socketIOClient.getBaseClient(),
                socketIOClient.getBaseClient().getCurrentTransport()));
    }

    public static ChannelFuture sendLoginMesage(Channel channel, Object obj) {
        if (channel == null || (!channel.isWritable())) {
            return null;
        }
        return channel.writeAndFlush(obj);
    }

    public static QuitUserResp getQuitUser(IMSession session) {
        return QuitUserResp.builder().userId(session.getUserId())
                .realname(session.getRealname())
                .role(session.getRole())
                .roomName(session.getRoomName())
                .groupName(session.getGroupName())
                .deviceType(session.getDeviceType())
                .socketId(session.getSid())
                .loginTime(session.getLoginTime()).build();
    }

    public static User getUser(IMSession session) {
        return User.builder().userId(session.getUserId())
                .role(session.getRole())
                .roomName(session.getRoomName())
                .groupName(session.getGroupName())
                .socketId(session.getSid())
                .loginTime(session.getLoginTime())
                .realname(session.getRealname() == null ? "" : session.getRealname())
                .avatar(session.getAvatar())
                .isBase64(false)
                .deviceType(session.getDeviceType())
                .build();
    }

    /**
     * 获取进出用户
     *
     * @param session
     * @return
     */
    public static LiveJoinDetail getLiveJoinDetail(IMSession session) {
        return LiveJoinDetail.builder().userId(session.getUserId())
                .role(session.getRole().getValue())
                .time(DateUtil.format(new Date(), DateUtil.DATE_FORMAT_YYYY_MM_DD_HH_MM_SS))
                .roomId(session.getRoomName())
                .groupId(session.getGroupName())
                .clientType(StrUtil.isBlank(session.getDeviceType()) ? "pc" : session.getDeviceType())
                .build();
    }
}
